package org.example.hrpc.common;

import org.example.hrpc.common.utils.ArrayUtils;
import org.example.hrpc.common.utils.CollectionUtils;
import org.example.hrpc.common.utils.StringUtils;

import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

public class URL implements Serializable {

    private static final long serialVersionUID = -1985165475234910535L;

    protected String protocol;

    protected String username;

    protected String password;

    // by default, host to registry
    protected String host;

    // by default, port to registry
    protected int port;

    // path是实际interfaceName 不是 interfaceClass
    protected String path;

    protected String[] paramTypes;

    protected Object[] arguments;

    // url 中 ？ 后面的部分, 以 & 分割 ，形如 key=value
    protected String[] parameters;

    public static String encode(String value) {
        if (StringUtils.isEmpty(value)) {
            return "";
        }
        try {
            return URLEncoder.encode(value, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    public static String decode(String value) {
        if (StringUtils.isEmpty(value)) {
            return "";
        }
        try {
            return URLDecoder.decode(value, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }


    public URL(String protocol, String username, String password, String host, int port,
               String path, String[] paramTypes, Object[] arguments, String[] parameters) {
        this.protocol = protocol;
        this.username = username;
        this.password = password;
        this.host = host;
        this.port = port;
        this.path = path;
        this.paramTypes = paramTypes;
        this.arguments = arguments;
        this.parameters = parameters;
    }

    public URL(String protocol, String host, int port, String path, String[] parameters) {
        this(protocol, null, null, host, port, path, null, null, parameters);
    }

    public String getProtocol() {
        return protocol;
    }

    public void setProtocol(String protocol) {
        this.protocol = protocol;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }

    public String[] getParamTypes() {
        return paramTypes;
    }

    public void setParamTypes(String[] paramTypes) {
        this.paramTypes = paramTypes;
    }

    public Object[] getArguments() {
        return arguments;
    }

    public void setArguments(Object[] arguments) {
        this.arguments = arguments;
    }

    public String[] getParameters() {
        return parameters;
    }

    public void setParameters(String[] parameters) {
        this.parameters = parameters;
    }


    public String getParameter(String key) {
        if(this.parameters != null) {
            for(String param : parameters) {
                if(StringUtils.isNotEmpty(param) && param.startsWith(key)) {
                    // key=value
                    // key=  共占 4字符，key长度为3，
                    return param.substring(key.length() + 1);
                }
            }
        }
        return null;
    }

    public SocketAddress getSocketAddress() {
        return InetSocketAddress.createUnresolved(host, port);
    }

    public String toFullString() {
        return  buildString(false, true, true);
    }

    public String toServiceStringWithoutResolving() {
        return buildString(true, false, true);
    }

    private String buildString(boolean appendUser, boolean appendParameter, boolean useService, String... parameters) {
        StringBuilder buf = new StringBuilder();
        if (StringUtils.isNotEmpty(protocol)) {
            buf.append(protocol);
            buf.append("://");
        }
        if (appendUser && StringUtils.isNotEmpty(username)) {
            buf.append(username);
            if (StringUtils.isNotEmpty(password)) {
                buf.append(":");
                buf.append(password);
            }
            buf.append("@");
        }
        String host = getHost();
        if (StringUtils.isNotEmpty(host)) {
            buf.append(host);
            if (port > 0) {
                buf.append(":");
                buf.append(port);
            }
        }
        String path;
        if (useService) {
            path = getServiceKey();
        } else {
            path = getPath();
        }
        if (StringUtils.isNotEmpty(path)) {
            buf.append("/");
            buf.append(path);
        }

        if (appendParameter) {
            buildParameters(buf, true, parameters);
        }
        return buf.toString();
    }

    /**
     * The format of return value is '{group}/{interfaceName}:{version}'
     *
     * @return
     */
    public String getServiceKey() {
        String inf = getPath();
        if (inf == null) {
            return null;
        }
        String serviceKey = inf;
        return serviceKey;
    }

    private void buildParameters(StringBuilder buf, boolean concat, String[] parameters) {
//        if (CollectionUtils.isNotEmptyMap(getParameters())) {
//            List<String> includes = (ArrayUtils.isEmpty(parameters) ? null : Arrays.asList(parameters));
//            boolean first = true;
//            for (Map.Entry<String, String> entry : new TreeMap<>(getParameters()).entrySet()) {
//                if (StringUtils.isNotEmpty(entry.getKey())
//                        && (includes == null || includes.contains(entry.getKey()))) {
//                    if (first) {
//                        if (concat) {
//                            buf.append("?");
//                        }
//                        first = false;
//                    } else {
//                        buf.append("&");
//                    }
//                    buf.append(entry.getKey());
//                    buf.append("=");
//                    buf.append(entry.getValue() == null ? "" : entry.getValue().trim());
//                }
//            }
//        }
    }

    @Override
    public String toString() {
        return "URL{" +
                "protocol='" + protocol + '\'' +
                ", host='" + host + '\'' +
                ", port=" + port +
                ", path='" + path + '\'' +
                ", parameters=" + Arrays.toString(parameters) +
                '}';
    }
}
